package model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.TreeMap;

import util.Stemmer;

public class ModeloVetorial {

	//Vetor de pesos para cada documento - modelo vetorial
	TreeMap<String,double[]> documentos = new TreeMap<String, double[]>();
	InvIndex index;
	
	public ModeloVetorial(InvIndex indice) {
		this.index = indice;
	}
	
	public void criarVetoresDocs() {
		//preenche o treemap documento x vetor de doubles, onde cada posicao representa uma palavra no vocabulario e leva um valor importancia dakela palavra no doc
		
		
		//Montando os vetores para os documentos e o da consulta
		Iterator<String> it = index.indice.keySet().iterator(); //varrendo o vocabulario de palavras (chaves do indice invertido)
		int nPalavras = 0;
		
		while(it.hasNext())
		{ //palavra por palavra do vocabulario
			String palavra = it.next();

			double[] temp;

			for(String arquivo : index.fileList)
			{
				if(this.documentos.containsKey(arquivo))
					temp = this.documentos.get(arquivo); //recupero existente
				else
					temp = new double[index.indice.keySet().size()]; //crio novo
	
				temp[nPalavras] = idf(palavra) * ocorrenciasArquivo(palavra, arquivo);
				
				this.documentos.put(arquivo, temp);
			}
			
			nPalavras++;
		}
		
	}
	

	
	public ArrayList<DocSimilar> consulta(String query, boolean stem) {
	
		Stemmer stemmer = new Stemmer();
		
		Hashtable<String,Integer> consulta = new Hashtable<String, Integer>();
		double[] queryVector = new double[this.index.indice.keySet().size()];
		
		//Processando a consulta
		String[] termosBusca = query.trim().split(" ");
		for(String s : termosBusca)
		{
			String wordStemmed;
			
			if(stem)
				wordStemmed = stemmer.getStemmed(s).trim();
			else
				wordStemmed = s.trim();

			if(consulta.containsKey(wordStemmed))
			{
				Integer freq = consulta.get(wordStemmed);
				freq++;
				consulta.put(wordStemmed,freq);
			}
			else
				consulta.put(wordStemmed,1);
		}	
		//hashtable palavra x contador montado p/ cada palavra da consulta

		//Montar vetor consulta
		Iterator<String> it = index.indice.keySet().iterator(); //varrendo o vocabulario de palavras (chaves do indice invertido)
		int counter = 0;
		
		while(it.hasNext())
		{ //palavra por palavra do vocabulario
			String palavra = it.next();		
			int vezes;
			
			if(consulta.get(palavra) == null) vezes = 0;
			else vezes = consulta.get(palavra);
			
			queryVector[counter] = idf(palavra) * vezes;
			counter++;
		}
	
		//Vetores montados
		//Agora, comparar vetor consulta com cada vetor documento calculando a similaridade
		
		List<DocSimilar> resposta = new ArrayList<DocSimilar>();
		for(String arquivo: this.index.fileList)
		{			
			double similaridade = this.similaridade(documentos.get(arquivo),queryVector);

			if(similaridade >= 0.4)
			{
				DocSimilar ds = new DocSimilar(arquivo,similaridade);
				resposta.add(ds);
			}

		}
		Collections.sort(resposta);
		return (ArrayList<DocSimilar>) resposta;
	}
	
	
	private double similaridade(double[] docVector, double[] queryVector) {
		
		double numerador = 0;
		double moduloDoc = 0;
		
		for(int i=0 ; i < docVector.length ; i++) 
		{
			numerador += docVector[i] * queryVector[i];
			moduloDoc += Math.pow(docVector[i], 2);
		}

		double moduloQuery = 0;
		for(int i=0 ; i < queryVector.length ; i++) 
			moduloQuery += Math.pow(queryVector[i], 2);
			

		moduloDoc = (double) Math.sqrt(moduloDoc);
		moduloQuery = (double) Math.sqrt(moduloQuery);
			
		if (moduloDoc == 0 || moduloQuery == 0)
			return 0;
		else
			return (numerador / (moduloDoc * moduloQuery));
		
	}
	
	/**
	 * 
	 * @param word
	 * @param fileName
	 * @return
	 */
	public int ocorrenciasArquivo(String word, String fileName)
	{
		int ocorrencias = 0;
		if(this.index.indice.get(word) != null) {
			
			for(Item i: this.index.indice.get(word))
			{
				if(i.getFile().equals(fileName))
					ocorrencias =  i.getOcorrencias();
			}
			
		}
		return ocorrencias;
		
	}
	
	public int ocorrenciasGeral(String word) { //numero de documentos em que a palavra ocorreu
		
		int ocorrencias = 0;
		if(this.index.indice.get(word) != null) {
			
			for(Item i: this.index.indice.get(word))
				if(i.getOcorrencias() >= 1) ocorrencias++;

		}
		return ocorrencias;
		
	}

	public double idf(String word)
	{
		int nDocs = this.index.fileList.size(); //numero total de documentos vistos pelo sistema	
		return java.lang.Math.log10((double)nDocs/(double)ocorrenciasGeral(word));
		
	}
	
	
	
}
